package mycomponents
{
	import flash.xml.XMLDocument;
	import flash.xml.XMLNode;
	
	import mx.utils.ObjectUtil;
	
	public class MyXmlEncoder
	{
		/**
		 *当有数组时子元素的标签名称 
		 */ 
		public var item:String="item";
		/**
		 * @private
		 */
		static internal function encodeDate(rawDate:Date, dateType:String):String
		{
			var s:String = new String();
			var n:Number;
			
			if (dateType == "dateTime" || dateType == "date")
			{
				s = s.concat(rawDate.getUTCFullYear(), "-");
				
				n = rawDate.getUTCMonth()+1;
				if (n < 10) s = s.concat("0");
				s = s.concat(n, "-");
				
				n = rawDate.getUTCDate();
				if (n < 10) s = s.concat("0");
				s = s.concat(n);
			}
			
			if (dateType == "dateTime")
			{
				s = s.concat("T");
			}
			
			if (dateType == "dateTime" || dateType == "time")
			{
				n = rawDate.getUTCHours();
				if (n < 10) s = s.concat("0");
				s = s.concat(n, ":");
				
				n = rawDate.getUTCMinutes();
				if (n < 10) s = s.concat("0");
				s = s.concat(n, ":");
				
				n = rawDate.getUTCSeconds();
				if (n < 10) s = s.concat("0");
				s = s.concat(n, ".");
				
				n = rawDate.getUTCMilliseconds();
				if (n < 10) s = s.concat("00");
				else if (n < 100) s = s.concat("0");
				s = s.concat(n);
			}
			
			s = s.concat("Z");
			
			return s;
		}
		
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		
		/**
		 *  Constructor.
		 *
		 *  @param myXML The XML object.
		 */
		public function MyXmlEncoder(myXML:XMLDocument)
		{
			super();
			
			this.myXMLDoc = myXML ? myXML : new XMLDocument();
		}
		
		//--------------------------------------------------------------------------
		//
		//  Variables
		//
		//--------------------------------------------------------------------------
		
		private var myXMLDoc:XMLDocument;
		
		//--------------------------------------------------------------------------
		//
		//  Methods
		//
		//--------------------------------------------------------------------------
		
		/**
		 *  Encodes an ActionScript object to XML using default serialization.
		 *  
		 *  @param obj The ActionScript object to encode.
		 *  
		 *  @param qname The qualified name of the child node.
		 *  
		 *  @param parentNode An XMLNode under which to put the encoded
		 *  value.
		 * 
		 *
		 *  
		 *  @langversion 3.0
		 *  @playerversion Flash 9
		 *  @playerversion AIR 1.1
		 *  @productversion Flex 3
		 *
		 *  @return The XMLNode object. 
		 */
		public function encodeValue(obj:Object, qname:QName, parentNode:XMLNode):XMLNode
		{
			var myElement:XMLNode;
			
			if (obj == null)
				return null;
			
			// Skip properties that are functions
			var typeType:uint = getDataTypeFromObject(obj);
			if (typeType == MyXmlEncoder.FUNCTION_TYPE)
				return null;
			
			if (typeType == MyXmlEncoder.XML_TYPE)
			{
				myElement = obj.cloneNode(true);
				parentNode.appendChild(myElement);
				return myElement;
			}
			
			myElement = myXMLDoc.createElement("foo");
			myElement.nodeName = qname.localName;
			parentNode.appendChild(myElement);
			
			if (typeType == MyXmlEncoder.OBJECT_TYPE)
			{
				var classInfo:Object = ObjectUtil.getClassInfo(obj, null, CLASS_INFO_OPTIONS);
				var properties:Array = classInfo.properties;
				var pCount:uint = properties.length;
				for (var p:uint = 0; p < pCount; p++)
				{
					var fieldName:String = properties[p];
					var propQName:QName = new QName("", fieldName);
					encodeValue(obj[fieldName], propQName, myElement);
				}
			}
			else if (typeType == MyXmlEncoder.ARRAY_TYPE)
			{
				var numMembers:uint = obj.length;
				var itemQName:QName = new QName("", item);
				
				for (var i:uint = 0; i < numMembers; i++)
				{
					encodeValue(obj[i], itemQName, myElement);
				}
			}
			else
			{
				// Simple types fall through to here
				var valueString:String;
				
				if (typeType == MyXmlEncoder.DATE_TYPE)
				{
					valueString = encodeDate(obj as Date, "dateTime");
				}
				else if (typeType == MyXmlEncoder.NUMBER_TYPE)
				{
					if (obj == Number.POSITIVE_INFINITY)
						valueString = "INF";
					else if (obj == Number.NEGATIVE_INFINITY)
						valueString = "-INF";
					else
					{
						var rep:String = obj.toString();
						// see if its hex
						var start:String = rep.substr(0, 2);
						if (start == "0X" || start == "0x")
						{
							valueString = parseInt(rep).toString();
						}
						else
						{
							valueString = rep;
						}
					}
				}
				else
				{
					valueString = obj.toString();
				}
				
				var valueNode:XMLNode = myXMLDoc.createTextNode(valueString);
				myElement.appendChild(valueNode);
			}
			
			return myElement;
		}
		
		/**
		 *  @private
		 */
		private function getDataTypeFromObject(obj:Object):uint
		{
			if (obj is Number)
				return MyXmlEncoder.NUMBER_TYPE;
			else if (obj is Boolean)
				return MyXmlEncoder.BOOLEAN_TYPE;
			else if (obj is String)
				return MyXmlEncoder.STRING_TYPE;
			else if (obj is XMLDocument)
				return MyXmlEncoder.XML_TYPE;
			else if (obj is Date)
				return MyXmlEncoder.DATE_TYPE;
			else if (obj is Array)
				return MyXmlEncoder.ARRAY_TYPE;
			else if (obj is Function)
				return MyXmlEncoder.FUNCTION_TYPE;
			else if (obj is Object)
				return MyXmlEncoder.OBJECT_TYPE;
			else
				// Otherwise force it to string
				return MyXmlEncoder.STRING_TYPE;
		}
		
		
		private static const NUMBER_TYPE:uint   = 0;
		private static const STRING_TYPE:uint   = 1;
		private static const OBJECT_TYPE:uint   = 2;
		private static const DATE_TYPE:uint     = 3;
		private static const BOOLEAN_TYPE:uint  = 4;
		private static const XML_TYPE:uint      = 5;
		private static const ARRAY_TYPE:uint    = 6;  // An array with a wrapper element
		private static const MAP_TYPE:uint      = 7;
		private static const ANY_TYPE:uint      = 8;
		// We don't appear to use this type anywhere, commenting out
		//private static const COLL_TYPE:uint     = 10; // A collection (no wrapper element, just maxOccurs)
		private static const ROWSET_TYPE:uint   = 11;
		private static const QBEAN_TYPE:uint    = 12; // CF QueryBean
		private static const DOC_TYPE:uint      = 13;
		private static const SCHEMA_TYPE:uint   = 14;
		private static const FUNCTION_TYPE:uint = 15; // We currently do not serialize properties of type function
		private static const ELEMENT_TYPE:uint  = 16;
		private static const BASE64_BINARY_TYPE:uint = 17;
		private static const HEX_BINARY_TYPE:uint = 18;
		
		/**
		 * @private
		 */
		private static const CLASS_INFO_OPTIONS:Object = {includeReadOnly:false, includeTransient:false};
	}
}